use anyhow::{Result, anyhow};

/// 单测站多通道数据矩阵
pub struct SingleStationDataMatrix {
    channel_count: usize,
    max_sample_count: usize,
    boardid: i32,
    start_time: f64,
    end_time: f64,
    data: Vec<f32>,
    actual_lengths: Vec<usize>,
}

impl SingleStationDataMatrix {
    pub fn new(
        channel_count: usize,
        max_sample_count: usize,
        boardid: i32,
        start_time: f64,
        end_time: f64,
    ) -> Result<Self> {
        if channel_count == 0 {
            return Err(anyhow!("通道数必须大于 0"));
        }
        if max_sample_count == 0 {
            return Err(anyhow!("最大样本数必须大于 0"));
        }
        if (end_time - start_time) <= 0.0 {
            return Err(anyhow!("结束时间必须大于开始时间"));
        }
        Ok(Self {
            channel_count,
            max_sample_count,
            boardid,
            start_time,
            end_time,
            data: vec![0.0; channel_count * max_sample_count],
            actual_lengths: vec![0; channel_count],
        })
    }

    #[inline]
    fn offset(&self, channel: usize, sample: usize) -> Result<usize> {
        if channel >= self.channel_count {
            return Err(anyhow!(
                "通道索引越界: {} / {}",
                channel,
                self.channel_count
            ));
        }
        if sample >= self.max_sample_count {
            return Err(anyhow!(
                "样本索引越界: {} / {}",
                sample,
                self.max_sample_count
            ));
        }
        Ok(channel * self.max_sample_count + sample)
    }

    pub fn write_sample(&mut self, channel: usize, sample: usize, value: f32) -> Result<()> {
        let idx = self.offset(channel, sample)?;
        self.data[idx] = value;
        if self.actual_lengths[channel] < sample + 1 {
            self.actual_lengths[channel] = sample + 1;
        }
        Ok(())
    }

    pub fn channel_count(&self) -> usize {
        self.channel_count
    }

    pub fn max_sample_count(&self) -> usize {
        self.max_sample_count
    }

    pub fn data(&self) -> &[f32] {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut [f32] {
        &mut self.data
    }

    pub fn actual_lengths(&self) -> &[usize] {
        &self.actual_lengths
    }

    pub fn actual_lengths_mut(&mut self) -> &mut [usize] {
        &mut self.actual_lengths
    }

    pub fn boardid(&self) -> i32 {
        self.boardid
    }

    pub fn start_time(&self) -> f64 {
        self.start_time
    }

    pub fn end_time(&self) -> f64 {
        self.end_time
    }
}
